﻿using MathNet.Numerics.LinearAlgebra.Double;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace TugasAkhir.Helpers
{
    public class FuzzyCalculation
    {
        private int jumlahData;
        private int jumlahA;

        private int[] kehadiran;
        private double[] nilai;
        private double[,] A;

        public FuzzyCalculation(int jumlahData, int jumlahA)
        {
            this.jumlahData = jumlahData;
            this.jumlahA = jumlahA;

            this.kehadiran = new int[this.jumlahData];
            this.nilai = new double[this.jumlahData];
            this.A = new double[this.jumlahData, this.jumlahA];
        }

        public void InitKehadiran(int[] kehadiran)
        {
            if (kehadiran.GetLength(0) != this.jumlahData)
            {
                throw new Exception(string.Format("Dimensi array harus {0}", this.jumlahData));
            }

            this.kehadiran = kehadiran;
        }

        public void InitNilai(double[] nilai)
        {
            if (nilai.GetLength(0) != this.jumlahData)
            {
                throw new Exception(string.Format("Dimensi array harus {0}", this.jumlahData));
            }

            this.nilai = nilai;
        }

        public void InitA(double[,] A)
        {
            if (A.GetLength(0) != this.jumlahData || A.GetLength(1) != this.jumlahA)
            {
                throw new Exception(string.Format("Dimensi array harus {0} x {1}", this.jumlahData, this.jumlahA));
            }
            this.A = A;
        }

        public void Calculate(out List<double> A, out List<double> AKehadiran)
        {
            int maksKehadiran = this.kehadiran.Max();

            var MatX = this.GetMatX();
            var MatY = this.GetMatY();

            var MatXTranspose = MatX.Transpose();

            var MatGs = this.GetMatGs();

            A = new List<double>();
            AKehadiran = new List<double>();

            for (int i = 0; i < MatGs.GetLength(0); i++)
            {
                var GX = MatGs[i].Multiply(MatX);
                var XTransposeGX = MatXTranspose.Multiply(GX);
                //Console.WriteLine(XTransposeGX.ToString());

                var GY = MatGs[i].Multiply(MatY);
                var XTransposeGY = MatXTranspose.Multiply(GY);
                //Console.WriteLine(XTransposeGY.ToString());

                double aTemp = 1.0 / XTransposeGX.At(0, 0) * XTransposeGY.At(0, 0);
                //Console.WriteLine(aTemp);
                //Console.WriteLine(aTemp / (double)maksKehadiran);

                //Console.WriteLine();
                A.Add(aTemp);
                AKehadiran.Add(aTemp / (double)maksKehadiran);
            }
        }

        private DenseMatrix GetMatX()
        {
            int maksKehadiran = this.kehadiran.Max();

            double[,] Xs = new double[this.jumlahData, 1];
            for (int i = 0; i < Xs.GetLength(0); i++)
            {
                Xs[i, 0] = (double)this.kehadiran[i] / (double)maksKehadiran;
            }

            return DenseMatrix.OfArray(Xs);
        }

        private DenseMatrix GetMatY()
        {
            double[,] Ys = new double[this.jumlahData, 1];
            for (int i = 0; i < Ys.GetLength(0); i++)
            {
                Ys[i, 0] = this.nilai[i];
            }

            return DenseMatrix.OfArray(Ys);
        }

        private DenseMatrix[] GetMatGs()
        {
            int maksKehadiran = this.kehadiran.Max();

            double[,] newA = this.A;
            for (int i = 0; i < newA.GetLength(0); i++)
            {
                for (int j = 0; j < newA.GetLength(1); j++)
                {
                    newA[i, j] = newA[i, j] / (double)maksKehadiran;
                }
            }

            double[][,] Gs = new double[this.jumlahA][,];
            for (int i = 0; i < Gs.GetLength(0); i++)
            {
                Gs[i] = new double[this.jumlahData, this.jumlahData];
                for (int j = 0; j < Gs[i].GetLength(0); j++)
                {
                    for (int k = 0; k < Gs[i].GetLength(1); k++)
                    {
                        if (j == k)
                        {
                            Gs[i][j, k] = newA[k, i];
                        }
                    }
                }
            }

            var MatGs = new DenseMatrix[this.jumlahA];
            for (int i = 0; i < MatGs.GetLength(0); i++)
            {
                MatGs[i] = DenseMatrix.OfArray(Gs[i]);
            }

            return MatGs;
        }
    }
}